package com.mjk.common.tools.jna;


import com.mjk.common.tools.logger.BizLogger;
import com.mjk.common.util.ClassUtil;
import com.mjk.common.util.FileUtils;
import com.mjk.common.util.ObjectUtils;
import com.mjk.common.util.StrUtils;
import com.sun.jna.Library;
import com.sun.jna.Native;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * dll 动态库
 *
 * @author mjk
 */
@Configuration
@ConditionalOnProperty(value = "dll.path")
public class DllConfig implements ApplicationContextAware {
	@Value("${dll.path}")
	public String DLL_PATH;

	private String absolutePath;

	private Set<Class<?>> setLib;

	/**
	 * 初始化DLL .dll放在DLL_PATH + Interface类名得 目录下
	 * 1 定义一个接口，继承library
	 * 2吧dll拷贝到DLL_PATH + Interface类名得 目录下
	 * 3使用JNADllCall.invokeMethod方法调用 JNI 函数
	 *
	 * @return
	 */
	@Bean
	public JNADllCall getJnaDllCall() {
		Map<String, Object> libMap = new HashMap<String, Object>();
		for (Class<?> clazz : setLib) {
			List<File> strList = FileUtils.loopFiles(absolutePath + clazz.getSimpleName(), "dll");
			if (ObjectUtils.isEmpty(strList)) {
				return null;
			}
			String name = "";
			try {
				Field f = clazz.getField("LibraryName");
				name = (String) f.get(null);

			} catch (Exception e) {
				BizLogger.info("LibraryName field is not exit");
			}
			String encode = "";
			try {
				Field encoding = clazz.getField("ENCODING");
				encode = (String) encoding.get(null);
			} catch (Exception e) {
				//do notiong
			}
			//设置初始化jna编码
			if (ObjectUtils.isNotEmpty(encode)) {
				System.setProperty("jna.encoding", encode);
			}
			if (ObjectUtils.isEmpty(name)) {
				name = strList.get(0).getName();
			}
			name = name.contains(".") ? name.substring(0, name.indexOf(".")) : name;

			libMap.put(clazz.getSimpleName(), Native.loadLibrary(name, clazz));
		}
		JNADllCall dll = new JNADllCall(libMap);
		return dll;
	}

	/**
	 * 解决JNA dll路径问题
	 */
	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		setLib = ClassUtil.scanPackageBySuper("com.ld", true, Library.class);
		absolutePath = getDllPath();
		List<String> path = new ArrayList<String>();
		for (Class<?> clazz : setLib) {
			path.add(absolutePath + clazz.getSimpleName() + "\\");
		}
		System.getProperties().setProperty("jna.library.path", StrUtils.join(path, ";"));
	}

	/**
	 * @param libraryPath
	 */
	public void addLibraryDir(String libraryPath) {
		try {
			System.out.println("libPath:" + libraryPath);
			Field field = ClassLoader.class.getDeclaredField("usr_paths");
			field.setAccessible(true);
			String[] paths = (String[]) field.get(null);
			for (int i = 0; i < paths.length; i++) {
				if (libraryPath.equals(paths[i])) {
					return;
				}
			}
			String[] tmp = new String[paths.length + 1];
			System.arraycopy(paths, 0, tmp, 0, paths.length);
			tmp[paths.length] = libraryPath;
			field.set(null, tmp);
		} catch (Exception e) {
			BizLogger.error(e);
		}
	}

	public String getDllPath() {
		try {
			File path = new File(ResourceUtils.getURL(DLL_PATH).getPath());
			String dllPath = path.getAbsolutePath();
			if (dllPath.endsWith("\\")) {
				return dllPath;
			} else {
				return path.getAbsolutePath() + "\\";
			}
		} catch (FileNotFoundException e1) {
			BizLogger.error(e1);
		}
		return null;
	}
}
